﻿using System;
using System.ComponentModel;
using System.IO;
using System.Windows.Input;
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
using Oxage.CNC.Hardware;
using Oxage.CNC.Models;
using Oxage.Common;

namespace Oxage.CNC.Commands
{
	public class MachineCommand : ICommand
	{
		#region Private properties
		public BackgroundWorker worker
		{
			get
			{
				//TODO: Move somewhere else for easier binding
				return ViewModel.View.worker;
			}
			set
			{
				ViewModel.View.worker = value;
			}
		}

		public IMachineController controller
		{
			get
			{
				return App.ViewModel.MachineController;
			}
		}
		#endregion
        
		#region Public properties
		public MainViewModel ViewModel
		{
			get;
			set;
		}
		#endregion

		#region ICommand Members
		public bool CanExecute(object parameter)
		{
			return true;
		}

		public event EventHandler CanExecuteChanged;
		protected virtual void OnCanExecuteChanged()
		{
			if (CanExecuteChanged != null)
			{
				CanExecuteChanged(this, new EventArgs());
			}
		}

		public void Execute(object parameter)
		{
			var command = parameter as string;
			switch (command)
			{
				case "Start":
					Start();
					break;

				case "Stop":
					Stop();
					break;
			}
		}
		#endregion

		#region Public methods
		public void Start()
		{
			try
			{
				if (controller == null)
				{
					throw new Exception("Controller is not initialized!");
				}

				Report("<open> " + controller.Name);
				controller.Open();

				//Get lines of G code
				string[] lines = ViewModel.Document.Content.Split(new char[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries);

				//Send line by line in another thread
				worker = new BackgroundWorker();
				worker.WorkerReportsProgress = true;
				worker.WorkerSupportsCancellation = true;
				worker.DoWork += (a, b) =>
				{
					//Send line by line and wait on each line until sent and processed
					foreach (string line in lines)
					{
						if (b.Cancel)
						{
							break;
						}

						Report("<sending> " + line);

						var model = new MachineDataModel();
						model.Line = line;

						//Serialize to BSON
						//Reference: http://james.newtonking.com/archive/2009/12/26/json-net-3-5-release-6-binary-json-bson-support.aspx
						byte[] data = null;
						using (MemoryStream ms = new MemoryStream())
						{
							JsonSerializer serializer = new JsonSerializer();
							BsonWriter writer = new BsonWriter(ms);
							serializer.Serialize(writer, model);
							data = ms.ToArray();
						}
						
						//Send raw data to a device
						controller.Write(data);
					}
				};
				worker.RunWorkerCompleted += (a, b) =>
				{
					//Sending completed
					Report("<close> " + controller.Name);
					controller.Close();
				};
				worker.RunWorkerAsync();
			}
			catch (Exception ex)
			{
				App.WriteLine(ex.Message);
			}
		}

		public void Stop()
		{
			try
			{
				if (controller == null)
				{
					throw new Exception("Controller is not initialized!");
				}

				if (worker != null && worker.IsBusy)
				{
					worker.CancelAsync();
				}

				Report("<close> " + controller.Name);
				controller.Close();
			}
			catch (Exception ex)
			{
				App.WriteLine(ex.Message);
			}
		}
		#endregion

		#region Protected methods
		protected void Report(string message)
		{
			//Invoke in GUI thread
			ViewModel.View.Dispatcher.Invoke((CrossThreadDelegate)delegate
			{
				App.WriteLine(message);
			});
		}
		#endregion

        public string Transform(Matrix podanaMatrika, string GCoda)
        {
            return newString;
        }
	}
}
